package session

import (
	"github.com/garyburd/redigo/redis"
	"github.com/satori/go.uuid"
	"sync"
	"time"
)

type RedisSessionMgr struct {
	adress     string
	password   string
	pool       *redis.Pool
	sessionMap map[string]Session
	rwMutex    sync.RWMutex
}

func NewRedisSessionMgr() SessionMgr {
	return &RedisSessionMgr{
		sessionMap: make(map[string]Session, 1024),
		rwMutex:    sync.RWMutex{},
	}
}

func newPool(server, password string) (pool *redis.Pool) {
	return &redis.Pool{
		Dial: func() (conn redis.Conn, e error) {
			conn, e = redis.Dial("tcp", server)
			if e != nil {
				return nil, e
			}
			return conn, e
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if time.Since(t) < time.Minute {
				return nil
			}
			_, err := c.Do("PING")
			return err
		},
		MaxIdle:         64,
		MaxActive:       1000,
		IdleTimeout:     240 * time.Second,
		Wait:            false,
		MaxConnLifetime: 0,
	}
}

func (r *RedisSessionMgr) Init(adress string, options ...interface{}) error {
	if len(options) > 0 {
		r.password = options[0].(string)
	}
	r.adress = adress
	r.pool = newPool(r.adress, r.password)
	return nil
}

func (r *RedisSessionMgr) Get(sessionId string) (session Session, err error) {
	r.rwMutex.RLock()
	defer r.rwMutex.RUnlock()
	session, ok := r.sessionMap[sessionId]
	if !ok {
		err = ErrSessionNotExist
	}
	return
}

func (r *RedisSessionMgr) CreateSession() (session Session, err error) {
	r.rwMutex.Lock()
	defer r.rwMutex.Unlock()
	id, err := uuid.NewV4()
	if err != nil {
		return
	}
	sessionId := id.String()
	session = NewRedisSession(sessionId, r.pool)
	r.sessionMap[sessionId] = session
	return
}
